//package cn.com.greatwall.system.modules.oauth2.config;
//
//import java.util.ArrayList;
//import java.util.HashMap;
//import java.util.HashSet;
//import java.util.List;
//import java.util.Map;
//import java.util.Objects;
//import java.util.Set;
//
//import javax.sql.DataSource;
//
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.beans.factory.annotation.Qualifier;
//import org.springframework.context.ApplicationContext;
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
//import org.springframework.data.redis.connection.RedisConnectionFactory;
//import org.springframework.http.HttpMethod;
//import org.springframework.security.authentication.AuthenticationManager;
//import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
//import org.springframework.security.config.annotation.web.builders.HttpSecurity;
//import org.springframework.security.config.http.SessionCreationPolicy;
//import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
//import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
//import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
//import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
//import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
//import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
//import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
//import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
//import org.springframework.security.oauth2.provider.ClientDetailsService;
//import org.springframework.security.oauth2.provider.OAuth2RequestFactory;
//import org.springframework.security.oauth2.provider.approval.UserApprovalHandler;
//import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
//import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices;
//import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory;
//import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter;
//import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
//import org.springframework.security.oauth2.provider.token.DefaultUserAuthenticationConverter;
//import org.springframework.security.oauth2.provider.token.TokenStore;
//import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
//import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
//import org.springframework.web.bind.annotation.RequestMethod;
//import org.springframework.web.filter.CorsFilter;
//import org.springframework.web.method.HandlerMethod;
//import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
//import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
//
//import cn.com.greatwall.common.annotation.AnonymousAccess;
//import cn.com.greatwall.common.utils.enums.RequestMethodEnum;
//import cn.com.greatwall.system.modules.oauth2.oauth.OauthUserApprovalHandler;
//import cn.com.greatwall.system.modules.oauth2.service.ClientDetailsServiceImpl;
//import cn.com.greatwall.system.modules.oauth2.service.CustomJdbcClientDetailsService;
//import cn.com.greatwall.system.modules.oauth2.service.OauthClientDetailsService;
//import cn.com.greatwall.system.modules.security.security.JwtAccessDeniedHandler;
//import cn.com.greatwall.system.modules.security.security.JwtAuthenticationEntryPoint;
//import cn.com.greatwall.system.modules.security.service.UserDetailsServiceImpl;
//import lombok.RequiredArgsConstructor;
//
///**
// * @Author herw
// * @Time 2020-10-23 13:10:52
// * @Version 1.0
// * @Description: TODO(用一句话描述该文件做什么)
// */
//@Configuration
//public class OAuth2ServerConfig {
//    private static final String DEMO_RESOURCE_ID = "greatwall";
//
//    @Configuration
//    @RequiredArgsConstructor
//    @EnableResourceServer
//    @EnableGlobalMethodSecurity(prePostEnabled = true)
//    protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
//        private final ApplicationContext applicationContext;
//        private final CorsFilter corsFilter;
//        private final JwtAuthenticationEntryPoint authenticationErrorHandler;
//        private final JwtAccessDeniedHandler jwtAccessDeniedHandler;
//        private final TokenStore tokenStore;
//
//        @Override
//        public void configure(ResourceServerSecurityConfigurer resources) {
//            resources.tokenStore(tokenStore).resourceId(DEMO_RESOURCE_ID);//.stateless(false);
//        }
//
////        @Override
////        public void configure(HttpSecurity http) throws Exception {
////            http
////                    // Since we want the protected resources to be accessible in the UI as well we
////                    // need
////                    // session creation to be allowed (it's disabled by default in 2.0.6)
////                    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED).and()
////                    .requestMatchers().anyRequest().and().anonymous().and().authorizeRequests()
////                    .antMatchers("/api/**").permitAll()
//////                  .antMatchers("/api/**").access("#oauth2.hasScope('select') and hasRole('ROLE_USER')")
////                    .antMatchers("/flowable/**").authenticated();// 配置api访问控制，必须认证过后才可以访问
////        }
//
//        /**
//         * 使用 permitAll() 方法所有人都能访问，包括带上 token 访问<br/>
//         * 使用 anonymous() 所有人都能访问，但是带上 token 访问后会报错
//         */
//        @Override
//        public void configure(HttpSecurity httpSecurity) throws Exception {
//            // 搜寻匿名标记 url： @AnonymousAccess
//            Map<RequestMappingInfo, HandlerMethod> handlerMethodMap = ((RequestMappingHandlerMapping) applicationContext
//                    .getBean("requestMappingHandlerMapping")).getHandlerMethods();
//            // 获取匿名标记
//            Map<String, Set<String>> anonymousUrls = getAnonymousUrl(handlerMethodMap);
//            httpSecurity.csrf().ignoringAntMatchers("/oauth/authorize", "/oauth/token", "/oauth/rest_token");
//            httpSecurity
//                    // 禁用 CSRF
//                    .csrf().disable().addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
//                    // 授权异常
//                    .exceptionHandling().authenticationEntryPoint(authenticationErrorHandler)
//                    .accessDeniedHandler(jwtAccessDeniedHandler)
//                    // 防止iframe 造成跨域
//                    .and().headers().frameOptions().disable()
//                    // 不创建会话
//                    .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
//                    .authorizeRequests()
//                    // 静态资源等等
//                    .antMatchers(HttpMethod.GET, "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/webSocket/**")
//                    .permitAll()
//                    // swagger 文档
//                    .antMatchers("/swagger-ui.html").permitAll().antMatchers("/swagger-resources/**").permitAll()
//                    .antMatchers("/webjars/**").permitAll().antMatchers("/*/api-docs").permitAll()
//                    // 文件
//                    .antMatchers("/avatar/**").permitAll().antMatchers("/file/**").permitAll()
//                    // 阿里巴巴 druid
//                    .antMatchers("/druid/**").permitAll()
//                    // Oauth2.0
//                    .antMatchers("/oauth/**","/authentication/base", "/auth/login").permitAll()
//                    // 放行OPTIONS请求
//                    .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
//                    // 自定义匿名访问所有url放行：允许匿名和带Token访问，细腻化到每个 Request 类型
//                    // GET
//                    .antMatchers(HttpMethod.GET,
//                            anonymousUrls.get(RequestMethodEnum.GET.getType()).toArray(new String[0]))
//                    .permitAll()
//                    // POST
//                    .antMatchers(HttpMethod.POST,
//                            anonymousUrls.get(RequestMethodEnum.POST.getType()).toArray(new String[0]))
//                    .permitAll()
//                    // PUT
//                    .antMatchers(HttpMethod.PUT,
//                            anonymousUrls.get(RequestMethodEnum.PUT.getType()).toArray(new String[0]))
//                    .permitAll()
//                    // PATCH
//                    .antMatchers(HttpMethod.PATCH,
//                            anonymousUrls.get(RequestMethodEnum.PATCH.getType()).toArray(new String[0]))
//                    .permitAll()
//                    // DELETE
//                    .antMatchers(HttpMethod.DELETE,
//                            anonymousUrls.get(RequestMethodEnum.DELETE.getType()).toArray(new String[0]))
//                    .permitAll()
//                    // 所有类型的接口都放行
//                    .antMatchers(anonymousUrls.get(RequestMethodEnum.ALL.getType()).toArray(new String[0])).permitAll()
//                    // 所有请求都需要认证
//                    .anyRequest().authenticated();
//        }
//
//        private Map<String, Set<String>> getAnonymousUrl(Map<RequestMappingInfo, HandlerMethod> handlerMethodMap) {
//            Map<String, Set<String>> anonymousUrls = new HashMap<>(6);
//            Set<String> get = new HashSet<>();
//            Set<String> post = new HashSet<>();
//            Set<String> put = new HashSet<>();
//            Set<String> patch = new HashSet<>();
//            Set<String> delete = new HashSet<>();
//            Set<String> all = new HashSet<>();
//            for (Map.Entry<RequestMappingInfo, HandlerMethod> infoEntry : handlerMethodMap.entrySet()) {
//                HandlerMethod handlerMethod = infoEntry.getValue();
//                AnonymousAccess anonymousAccess = handlerMethod.getMethodAnnotation(AnonymousAccess.class);
//                if (null != anonymousAccess) {
//                    List<RequestMethod> requestMethods = new ArrayList<>(
//                            infoEntry.getKey().getMethodsCondition().getMethods());
//                    RequestMethodEnum request = RequestMethodEnum
//                            .find(requestMethods.size() == 0 ? RequestMethodEnum.ALL.getType()
//                                    : requestMethods.get(0).name());
//                    switch (Objects.requireNonNull(request)) {
//                    case GET:
//                        get.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
//                        break;
//                    case POST:
//                        post.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
//                        break;
//                    case PUT:
//                        put.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
//                        break;
//                    case PATCH:
//                        patch.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
//                        break;
//                    case DELETE:
//                        delete.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
//                        break;
//                    default:
//                        all.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
//                        break;
//                    }
//                }
//            }
//            anonymousUrls.put(RequestMethodEnum.GET.getType(), get);
//            anonymousUrls.put(RequestMethodEnum.POST.getType(), post);
//            anonymousUrls.put(RequestMethodEnum.PUT.getType(), put);
//            anonymousUrls.put(RequestMethodEnum.PATCH.getType(), patch);
//            anonymousUrls.put(RequestMethodEnum.DELETE.getType(), delete);
//            anonymousUrls.put(RequestMethodEnum.ALL.getType(), all);
//            return anonymousUrls;
//        }
//    }
//
//    @Configuration
//    @EnableAuthorizationServer
//    protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
//        @Autowired
//        private TokenStore tokenStore;
//        @Autowired
//        private DefaultTokenServices tokenServices;
////        @Autowired
////        private ClientDetailsService clientDetailsService;
//        @Autowired
//        private ClientDetailsServiceImpl clientDetailsService;
////        @Autowired
////        private AuthorizationCodeServices authorizationCodeServices;
//        @Autowired
//        @Qualifier("authenticationManagerBean")
//        private AuthenticationManager authenticationManager;
//        @Autowired
//        private OauthClientDetailsService oauthService;
//        @Autowired
//        private UserDetailsServiceImpl userDetailsService;
//
//        @Override
//        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
//            // 配置客户端
//            clients.withClientDetails(clientDetailsService);
//        }
//
////      /*
////      * JDBC TokenStore
////      */
////     @Bean
////     public TokenStore tokenStore(DataSource dataSource) {
////         return new JdbcTokenStore(dataSource);
////     }
//
//        /*
//         * Redis TokenStore (有Redis场景时使用)
//         */
////     @Bean
////     public TokenStore tokenStore(RedisConnectionFactory connectionFactory) {
////         final RedisTokenStore redisTokenStore = new RedisTokenStore(connectionFactory);
////         //prefix
////         redisTokenStore.setPrefix(RESOURCE_ID);
////         return redisTokenStore;
////     }
//
//        @Override
//        public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
//            endpoints.tokenServices(tokenServices).tokenStore(tokenStore)
//                    .userDetailsService(userDetailsService)
//                    .authenticationManager(authenticationManager);
//            //.authorizationCodeServices(authorizationCodeServices).userApprovalHandler(userApprovalHandler())
//            
//            endpoints.pathMapping("/oauth/confirm_access","/custom/confirm_access");
//
////            DefaultAccessTokenConverter converter = new DefaultAccessTokenConverter();
////            DefaultUserAuthenticationConverter userAuthenticationConverter
////                = new DefaultUserAuthenticationConverter();
////            userAuthenticationConverter.setUserDetailsService(userDetailsService);
////            converter.setUserTokenConverter(userAuthenticationConverter);
////            endpoints.accessTokenConverter(converter);
//        }
//
//        @Override
//        public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
//            // 允许表单认证，支持 client_credentials 的配置
//
//            oauthServer.realm("greatwall")// real 值可自定义
//                    .allowFormAuthenticationForClients();// 支持 client_credentials 的配置
//            oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
//        }
//
//        @Bean
//        public ClientDetailsService clientDetailsService(DataSource dataSource) {
//            return new CustomJdbcClientDetailsService(dataSource);
//        }
//
////        @Bean
////        public AuthorizationCodeServices authorizationCodeServices(DataSource dataSource) {
////            return new JdbcAuthorizationCodeServices(dataSource);
////        }
//
//        @Bean
//        public OAuth2RequestFactory oAuth2RequestFactory() {
//            return new DefaultOAuth2RequestFactory(clientDetailsService);
//        }
//
////        @Bean
////        public UserApprovalHandler userApprovalHandler() {
////            OauthUserApprovalHandler userApprovalHandler = new OauthUserApprovalHandler();
////            userApprovalHandler.setOauthService(oauthService);
////            userApprovalHandler.setTokenStore(tokenStore);
////            userApprovalHandler.setClientDetailsService(this.clientDetailsService);
////            userApprovalHandler.setRequestFactory(oAuth2RequestFactory());
////            return userApprovalHandler;
////        }
//    }
//}
